#include "precompiled.h"
#include "prs_DataTree.h"
using namespace prs;

// TDataTreeRecord ////////////////////////////////////////////////////////////

//
TDataTreeRecord::TDataTreeRecord(
	TDataTree	&DataTree
):dataTree(DataTree) {
	childRecord = NULL;
	treeRecord = NULL;
	itemToTable = NULL;
	itemToRecord = NULL;
}

//
TDataTreeRecord::TDataTreeRecord(
  TDataTreeRecord	&DataTreeRecord
):dataTree(DataTreeRecord.dataTree) {
 *this = DataTreeRecord;
}

//
void TDataTreeRecord::SetItemName(const svl::TString &Value) {
  itemToRecord->SetValueForExplorer(Value);
}

//
svl::TString TDataTreeRecord::GetItemName() {
  svl::TString S;
  itemToRecord->GetValueForExplorer(S);
  return S;
}

//
void TDataTreeRecord::NewTreeRecord(
  const TTableId &ItemToTableId,
  const TRecordId &ItemToRecordId
){
	itemToTable = dataTree.tables.GetTable(ItemToTableId);
	itemToRecord = itemToTable->GetRecord(ItemToRecordId);
	
  treeRecord = dataTree.table->AddRecord();
  treeRecord->AddValueRefTR(
		dataTree.itemFieldId, 
		ItemToTableId,
		ItemToRecordId
	);
}

//
int TDataTreeRecord::GetChildrenCount() {
  TDataValueRefR *Children = treeRecord->GetValueRefR(
    dataTree.childrenFieldId
  );
	return Children->Value.Array.Count();
}

//
TDataTreeRecord TDataTreeRecord::GetChild(int NChild) {
  TDataValueRefR *Children = treeRecord->GetValueRefR(
    dataTree.childrenFieldId
  );

	TDataRefRRecord &ChildRecord = Children->Value.Array.Get(NChild);
	TDataTreeRecord TreeRecord = dataTree.GetRecord(TRecordId( ChildRecord.ToRecordId ));
	TreeRecord.childRecord = &ChildRecord;
								
	return TreeRecord;
}

//
TDataTreeRecord TDataTreeRecord::AddChildFirst(
  const TTableId &ItemToTableId,
  const TRecordId &ItemToRecordId
){
	TDataTreeRecord TreeRecord(dataTree);
		TreeRecord.NewTreeRecord(
			ItemToTableId,
			ItemToRecordId
		);

	TreeRecord.childRecord = treeRecord->AddValueRefRFirst(
	  dataTree.childrenFieldId, 
	  TRecordId( TreeRecord.treeRecord->RecordId )
	);

	return TreeRecord;
}

//
TDataTreeRecord TDataTreeRecord::AddChildLast(
  const TTableId &ItemToTableId,
  const TRecordId &ItemToRecordId
){
	TDataTreeRecord TreeRecord(dataTree);
		TreeRecord.NewTreeRecord(
		  ItemToTableId,
		  ItemToRecordId
		);

	TreeRecord.childRecord = treeRecord->AddValueRefRLast(
	  dataTree.childrenFieldId, 
	  TRecordId( TreeRecord.treeRecord->RecordId )
	);

	return TreeRecord;
}

//
TDataTreeRecord TDataTreeRecord::AddChildBefore(
  const TDataTreeRecord &Current,
  const TTableId &ItemToTableId,
  const TRecordId &ItemToRecordId
){
	if (!Current.childRecord) {
		Except("AddChildBefore[!Current.childRecord]");
	}

	TDataTreeRecord TreeRecord(dataTree);
		TreeRecord.NewTreeRecord(
		  ItemToTableId,
		  ItemToRecordId
		);

	TreeRecord.childRecord = treeRecord->AddValueRefRBefore(
	  dataTree.childrenFieldId, 
	  Current.childRecord,
	  TRecordId( TreeRecord.treeRecord->RecordId )
	);

	return TreeRecord;
}

//
TDataTreeRecord TDataTreeRecord::AddChildAfter(
  const TDataTreeRecord &Current,
  const TTableId &ItemToTableId,
  const TRecordId &ItemToRecordId
){
	if (!Current.childRecord) {
		Except("AddChildAfter[!Current.childRecord]");
	}

	TDataTreeRecord TreeRecord(dataTree);
		TreeRecord.NewTreeRecord(
		  ItemToTableId,
		  ItemToRecordId
		);

	TreeRecord.childRecord = treeRecord->AddValueRefRAfter(
	  dataTree.childrenFieldId, 
	  Current.childRecord,
	  TRecordId( TreeRecord.treeRecord->RecordId )
	);

	return TreeRecord;
}

// TDataTree //////////////////////////////////////////////////////////////////

//
TDataTree::TDataTree(
  TDataTables &Tables,
  const TTableId &TableId
)
:tables(Tables)
{
	itemFieldId = "item";
	childrenFieldId = "children";
	
	table = tables.GetTable(TableId);
	if (!table)	{
    table = tables.AddTable(TableId);
      table->AddFieldRefTR(itemFieldId);
      table->AddFieldRefR (childrenFieldId,TableId);
	}
}

//
TDataTreeRecord TDataTree::AddRootRecord(
  const TTableId &ItemTableId,
  const TRecordId &ItemRecordId
){
	TDataTreeRecord Record(*this);
		Record.NewTreeRecord(ItemTableId,ItemRecordId);
	return Record;
}

//
TDataTreeRecord TDataTree::AddRootRecord(const TDataTypedRecordBase &Record) { 
	return AddRootRecord(Record.GetTableId(),Record.GetRecordId());
}

//
TDataTreeRecord TDataTree::GetRecord(
  const TRecordId &TreeRecordId
){
	TDataTreeRecord TreeRecord(*this);

  TreeRecord.treeRecord = table->GetRecord(TreeRecordId);

  TDataValueRefTR  *ItemValue = TreeRecord.treeRecord->GetValueRefTR(itemFieldId);
  TDataRefTRRecord &ItemRecord = ItemValue->Value.Array.Get(0);

	TreeRecord.itemToTable  = tables.GetTable(ItemRecord.ToTableId);
	TreeRecord.itemToRecord = TreeRecord.itemToTable->GetRecord( ItemRecord.ToRecordId );

	return TreeRecord;
}
